/*
 * CDPSResults.java
 * 
 * Copyright (c) 2009 Giles Millward (Manigra). All rights reserved.
 * 
 * This file is part of JRogueDPS.
 * 
 * JRogueDPS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * JRogueDPS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with JRogueDPS.  If not, see <http://www.gnu.org/licenses/>.
 */

package dpsresults;

import dpsstats.CAllStats;
import dpsstats.CDamageStats;
import dpssystem.CUtil;
import java.awt.Color;
import java.awt.Font;
import java.awt.image.BufferedImage;
import java.text.DecimalFormat;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.table.TableModel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.entity.ChartEntity;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.labels.StandardXYToolTipGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.IntervalMarker;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.Layer;
import org.jfree.ui.RectangleAnchor;
import org.jfree.ui.TextAnchor;

/**
 *
 * @author Giles Millward (Manigra)
 */
public class CDPSResults {
    private CAllStats m_stats;
    private JTable m_damageTable;
    private JTable m_procsTable;
    private JTable m_regenTable;
    private JLabel m_overallPie1;
    private JLabel m_poisonPie1;
    private JLabel m_poisonPie2;
    private JPanel m_iterationGraph;
    private JLabel m_finisherDistribution;

    public void linkGUI(JTable p_damageTable,
                        JTable p_procsTable,
                        JTable p_regenTable,
                        JLabel p_poisonPie1,
                        JLabel p_poisonPie2,
                        JLabel p_overallPie1,
                        JPanel p_iterationGraph,
                        JLabel p_finisherDistribution)
    {
        m_damageTable = p_damageTable;
        m_procsTable = p_procsTable;
        m_regenTable = p_regenTable;
        m_poisonPie1 = p_poisonPie1;
        m_poisonPie2 = p_poisonPie2;
        m_overallPie1 = p_overallPie1;
        m_iterationGraph = p_iterationGraph;
        m_finisherDistribution = p_finisherDistribution;
        
        ((CDamageResultTable) m_damageTable.getModel()).addColumn("Damage Source");
        ((CDamageResultTable) m_damageTable.getModel()).addColumn("Damage");
        ((CDamageResultTable) m_damageTable.getModel()).addColumn("Normal");
        ((CDamageResultTable) m_damageTable.getModel()).addColumn("Crits");
        ((CDamageResultTable) m_damageTable.getModel()).addColumn("Misses");
        ((CDamageResultTable) m_damageTable.getModel()).addColumn("Glancing");
        ((CDamageResultTable) m_damageTable.getModel()).addColumn("Dodges");
        m_damageTable.setDefaultRenderer(CDamageStats.class, new CDamageResultRenderer());
    }

    public void updateResults(CAllStats p_stats, double p_averageDPS, double p_stdDeviation)
    {
        m_stats = p_stats;
        updateNumbersTable();
        updateProcsTable();
        updateRegenTable();
        updateOverallCharts();
        updatePoisonPieCharts();
        updateIterationGraph(m_iterationGraph, p_averageDPS, p_stdDeviation);
        updateFinisherDistributionStats(m_finisherDistribution);
    }

    private void updateNumbersTable()
    {
        CDamageResultTable l_resultTable = (CDamageResultTable) m_damageTable.getModel();

        l_resultTable.cleanRows();
        l_resultTable.addRow(m_stats.m_MHAutoAttack);
        l_resultTable.addRow(m_stats.m_OHAutoAttack);
        l_resultTable.addRow(m_stats.getTotalStats("AutoAttack Total", m_stats.m_autoAttackStats));
        l_resultTable.addRow(null);
        l_resultTable.addRow(m_stats.m_MHPoisonStats);
        l_resultTable.addRow(m_stats.m_OHPoisonStats);
        l_resultTable.addRow(null);
        l_resultTable.addRow(m_stats.m_deadlyPoisonDOTStats);
        l_resultTable.addRow(m_stats.m_ruptureDOTStats);
        l_resultTable.addRow(m_stats.m_garroteDOTStats);
        l_resultTable.addRow(null);
        l_resultTable.addRow(m_stats.m_mutilateStats);
        l_resultTable.addRow(m_stats.m_sinisterStrikeStats);
        l_resultTable.addRow(m_stats.m_backStabStats);
        l_resultTable.addRow(m_stats.m_ruptureStats);
        l_resultTable.addRow(m_stats.m_sliceAndDiceStats);
        l_resultTable.addRow(null);
        l_resultTable.addRow(m_stats.m_envenomStats);
        l_resultTable.addRow(m_stats.m_eviscerateStats);
    }

    void updateProcsTable()
    {
        TableModel l_table = m_procsTable.getModel();
        for (int i = 0; i < l_table.getRowCount(); i++)
        {
            l_table.setValueAt((String) "", i, 0);
            l_table.setValueAt((String) "", i, 1);
            l_table.setValueAt((String) "", i, 2);
        }
        
        for (int i = 0; i < m_stats.m_procStats.size(); i++)
        {
            l_table.setValueAt((String) "" + m_stats.m_procStats.get(i).m_name, i, 0);
            double l_procs = m_stats.m_procStats.get(i).m_procs;
            double l_procsPerMinute = 60.0 / (m_stats.m_runTime / (double) l_procs);
            double l_procUptime = m_stats.m_procStats.get(i).m_procUptime;
            double l_percentUptime = ((1 / m_stats.m_runTime) * l_procUptime) * 100.0;

            l_table.setValueAt((String) "" + CUtil.trunc2(l_procs) + " (" + CUtil.trunc2(l_procsPerMinute) + "ppm)", i, 1);
            l_table.setValueAt((String) "" + CUtil.trunc2(l_procUptime) + " (" + CUtil.trunc2(l_percentUptime) + "%)", i, 2);
        }

    }

    void updateRegenTable()
    {
        TableModel l_table = m_regenTable.getModel();
        for (int i = 0; i < l_table.getRowCount(); i++)
        {
            l_table.setValueAt((String) "", i, 0);
            l_table.setValueAt((String) "", i, 1);
        }
        
        for (int i = 0; i < m_stats.m_energyStats.size(); i++)
        {
            l_table.setValueAt((String) "" + m_stats.m_energyStats.get(i).m_name, i, 0);
            double l_energy = m_stats.m_energyStats.get(i).m_energyRegened;

            l_table.setValueAt((String) "" + l_energy, i, 1);
        }

    }

    private void updatePoisonPieCharts()
    {
        // Main hand/Off hand damage distribution first
        createMHOHPoisonDistribution(this.m_poisonPie1);
        createDeadlyPoisonStackStats(this.m_poisonPie2);
    }

    private void updateOverallCharts()
    {
        DefaultPieDataset l_dataSet = new DefaultPieDataset();
        l_dataSet.setValue("Auto Attack", m_stats.getTotalDamage(m_stats.m_autoAttackStats));
        l_dataSet.setValue("Deadly Poison", m_stats.getTotalPoison("Deadly"));
        l_dataSet.setValue("Instant Poison", m_stats.getTotalPoison("Instant"));
        l_dataSet.setValue("Anasthetic Poison", m_stats.getTotalPoison("Anasthetic"));
        l_dataSet.setValue("Wound Poison", m_stats.getTotalPoison("Wound"));
        l_dataSet.setValue("Mutilate", m_stats.m_mutilateStats.getTotalDamage());
        l_dataSet.setValue("Envenom", m_stats.m_envenomStats.getTotalDamage());
        l_dataSet.setValue("Rupture", m_stats.m_ruptureDOTStats.getTotalDamage());
        l_dataSet.setValue("Sinister Strike", m_stats.m_sinisterStrikeStats.getTotalDamage());
        l_dataSet.setValue("Eviscerate", m_stats.m_eviscerateStats.getTotalDamage());

        JFreeChart l_chart = ChartFactory.createPieChart
                     ("Overall Damage",   // Title
                      l_dataSet,           // Dataset
                      true,                  // Show legend
                      true,
                      false
                     );

        PiePlot l_plot = ( PiePlot )l_chart.getPlot();
        l_plot.setIgnoreZeroValues(true);
        l_plot.setSimpleLabels( true );
        l_plot.setLabelGenerator(new StandardPieSectionLabelGenerator("{0} {2}"));

        BufferedImage l_image = l_chart.createBufferedImage(m_overallPie1.getWidth(), m_overallPie1.getHeight());
        m_overallPie1.setIcon(new ImageIcon(l_image));
    }
    
    private void createMHOHPoisonDistribution(JLabel p_label)
    {
        DefaultPieDataset l_dataSet = new DefaultPieDataset();
        if (m_stats.m_MHPoisonStats.getName().equals("MH Deadly Poison") &&
            m_stats.m_OHPoisonStats.getName().equals("OH Deadly Poison"))
        {
            l_dataSet.setValue("Deadly Poison", m_stats.m_deadlyPoisonDOTStats.getTotalDamage());
        }
        else if (m_stats.m_MHPoisonStats.getName().equals("MH Deadly Poison"))
        {
            l_dataSet.setValue(m_stats.m_MHPoisonStats.getName(), m_stats.m_deadlyPoisonDOTStats.getTotalDamage());
            l_dataSet.setValue(m_stats.m_OHPoisonStats.getName(), m_stats.m_OHPoisonStats.getTotalDamage());
        } else if (m_stats.m_OHPoisonStats.getName().equals("OH Deadly Poison"))
        {
            l_dataSet.setValue(m_stats.m_MHPoisonStats.getName(), m_stats.m_MHPoisonStats.getTotalDamage());
            l_dataSet.setValue(m_stats.m_OHPoisonStats.getName(), m_stats.m_deadlyPoisonDOTStats.getTotalDamage());

        } else
        {
            l_dataSet.setValue(m_stats.m_MHPoisonStats.getName(), m_stats.m_MHPoisonStats.getTotalDamage());
            l_dataSet.setValue(m_stats.m_OHPoisonStats.getName(), m_stats.m_OHPoisonStats.getTotalDamage());
        }

        JFreeChart l_chart = ChartFactory.createPieChart
                     ("Poison Dmg",   // Title
                      l_dataSet,           // Dataset
                      true,                  // Show legend
                      true,
                      false
                     );

        PiePlot l_plot = ( PiePlot )l_chart.getPlot();
        l_plot.setSimpleLabels( true );
        l_plot.setLabelGenerator(new StandardPieSectionLabelGenerator("{0} {2}"));

        BufferedImage l_image = l_chart.createBufferedImage(p_label.getWidth(), p_label.getHeight());
        p_label.setIcon(new ImageIcon(l_image));
    }

    private void createDeadlyPoisonStackStats(JLabel p_label)
    {
        DefaultCategoryDataset l_dataSet = new DefaultCategoryDataset();
        l_dataSet.addValue(m_stats.m_deadlyPoisonStackStats.getTickCount(0), "Stack", "1");
        l_dataSet.addValue(m_stats.m_deadlyPoisonStackStats.getTickCount(1), "Stack", "2");
        l_dataSet.addValue(m_stats.m_deadlyPoisonStackStats.getTickCount(2), "Stack", "3");
        l_dataSet.addValue(m_stats.m_deadlyPoisonStackStats.getTickCount(3), "Stack", "4");
        l_dataSet.addValue(m_stats.m_deadlyPoisonStackStats.getTickCount(4), "Stack", "5");

        JFreeChart l_chart = ChartFactory.createBarChart(
            "DP Stacks", // chart title
            "Stack", // domain axis label
            "Ticks", // range axis label
            l_dataSet, // data
            PlotOrientation.VERTICAL, // orientation
            false, // include legend
            true, // tooltips?
            false // URLs?
            );        

        CategoryPlot l_plot = (CategoryPlot) l_chart.getPlot();
        BarRenderer renderer = (BarRenderer) l_plot.getRenderer();
        renderer.setDrawBarOutline(false);
        renderer.setMinimumBarLength(50);

        BufferedImage l_image = l_chart.createBufferedImage(p_label.getWidth(), p_label.getHeight());
        p_label.setIcon(new ImageIcon(l_image));
    }

    public void updateIterationGraph(JPanel p_panel, double p_averageDPS, double p_stdDeviation)
    {
        // TODO Mouse Handler for viewing logs
        XYSeries l_series = new XYSeries("Iteration DPS");
        for (int i = 0; i < m_stats.m_iterationDPS.size(); i++) {
            int x = i + 1;
            double y = m_stats.m_iterationDPS.get(i);
            l_series.add(x, y);
        }

        XYDataset l_data = new XYSeriesCollection(l_series);

        // create a scatter chart...
        final JFreeChart l_chart = ChartFactory.createScatterPlot(
            "DPS Per Iteration", "Iterations", "DPS",
            l_data,
            PlotOrientation.VERTICAL,
            false,
            false,
            false
        );

        final XYPlot l_plot = l_chart.getXYPlot();

        IntervalMarker l_stdDeviation = new IntervalMarker((p_averageDPS - p_stdDeviation), (p_averageDPS + p_stdDeviation));
        l_stdDeviation.setLabel("Std Deviation");
        l_stdDeviation.setLabelFont(new Font("SansSerif", Font.ITALIC, 11));
        l_stdDeviation.setLabelAnchor(RectangleAnchor.TOP_LEFT);
        l_stdDeviation.setLabelTextAnchor(TextAnchor.TOP_LEFT);
        l_stdDeviation.setPaint(new Color(222,222,255,128));
        l_plot.addRangeMarker(l_stdDeviation, Layer.BACKGROUND);

        IntervalMarker l_averageDPS = new IntervalMarker(p_averageDPS,p_averageDPS);
        l_averageDPS.setLabel("Average DPS");
        l_averageDPS.setLabelFont(new Font("SansSerif", Font.ITALIC, 11));
        l_averageDPS.setLabelAnchor(RectangleAnchor.LEFT);
        l_averageDPS.setLabelTextAnchor(TextAnchor.HALF_ASCENT_LEFT);
        l_averageDPS.setPaint(new Color(222,222,245,128));
        l_plot.addRangeMarker(l_averageDPS, Layer.BACKGROUND);

        XYItemRenderer l_itemRenderer = l_plot.getRenderer();
        StandardXYToolTipGenerator l_generator = new StandardXYToolTipGenerator(
                                "Iteration {1}/ DPS {2}", new DecimalFormat("0"), new DecimalFormat("0.00"));

        l_itemRenderer.setBaseToolTipGenerator(l_generator);

        ChartPanel l_chartPanel = new ChartPanel(l_chart);
        p_panel.removeAll();
        p_panel.add(l_chartPanel);
        l_chartPanel.setSize(p_panel.getSize());
        l_chartPanel.setMouseWheelEnabled(true);
        l_chartPanel.setDomainZoomable(false);
        l_chartPanel.setVisible(true);
        l_chartPanel.addChartMouseListener(new ChartMouseListener()
        {
            public void chartMouseClicked(ChartMouseEvent event)
            {
                ChartEntity l_entity = event.getEntity();
                if (l_entity != null)
                {
                    String l_toolTip = l_entity.getToolTipText();
                    if (l_toolTip != null)
                    {
                        int l_iteration = Integer.parseInt(l_toolTip.substring(10, l_toolTip.lastIndexOf("/")));
                        System.out.println("Test : " + l_iteration);
                        // TODO Fire off a popup window showing logs
                    }
                }
            }


            public void chartMouseMoved(ChartMouseEvent event)
            {

            }
        });
    }

    private void updateFinisherDistributionStats(JLabel p_label)
    {
        DefaultCategoryDataset l_dataSet = new DefaultCategoryDataset();
        for (int i = 0; i < m_stats.m_finisherStatsList.size(); i++)
        {
            if (m_stats.m_finisherStatsList.get(i).getTotal() != 0)
            {
                l_dataSet.addValue(m_stats.m_finisherStatsList.get(i).getFinisher(1), m_stats.m_finisherStatsList.get(i).m_name, "1");
                l_dataSet.addValue(m_stats.m_finisherStatsList.get(i).getFinisher(2), m_stats.m_finisherStatsList.get(i).m_name, "2");
                l_dataSet.addValue(m_stats.m_finisherStatsList.get(i).getFinisher(3), m_stats.m_finisherStatsList.get(i).m_name, "3");
                l_dataSet.addValue(m_stats.m_finisherStatsList.get(i).getFinisher(4), m_stats.m_finisherStatsList.get(i).m_name, "4");
                l_dataSet.addValue(m_stats.m_finisherStatsList.get(i).getFinisher(5), m_stats.m_finisherStatsList.get(i).m_name, "5");
            }
        }

        JFreeChart l_chart = ChartFactory.createBarChart(
            "Finisher Combo Point Distribution", // chart title
            "Combo Points", // domain axis label
            "Finisher Count", // range axis label
            l_dataSet, // data
            PlotOrientation.VERTICAL, // orientation
            true, // include legend
            true, // tooltips?
            false // URLs?
            );

        CategoryPlot l_plot = (CategoryPlot) l_chart.getPlot();
        BarRenderer renderer = (BarRenderer) l_plot.getRenderer();
        renderer.setDrawBarOutline(false);
        renderer.setMinimumBarLength(50);

        BufferedImage l_image = l_chart.createBufferedImage(p_label.getWidth(), p_label.getHeight());
        p_label.setIcon(new ImageIcon(l_image));
    }
}
